package org.linlinjava.litemall.wx.controller;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.linlinjava.litemall.core.util.JacksonUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.core.validator.Order;
import org.linlinjava.litemall.core.validator.Sort;
import org.linlinjava.litemall.db.beans.Constants;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.dto.WxMemberSourceDTO;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.wx.annotation.LogAnno;
import org.linlinjava.litemall.wx.annotation.LoginUser;
import org.linlinjava.litemall.wx.util.PageUtil;
import org.linlinjava.litemall.wx.util.WxResponseCode;
import org.linlinjava.litemall.wx.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * wx优惠券控制器
 * 优惠券服务
 *
 * @author yliyun
 * @date 2022/09/14
 */
@RestController
@RequestMapping("/wx/coupon")
@Validated
public class WxCouponController {

    /**
     * 息服务
     */
    @Autowired
    private LitemallCouponService couponService;
    /**
     * 优惠券用户服务
     */
    @Autowired
    private LitemallCouponUserService couponUserService;
    /**
     * 优惠券验证服务
     */
    @Autowired
    private CouponVerifyService couponVerifyService;

    /**
     * 用户服务
     */
    @Autowired
    private LitemallUserService userService;

    /**
     * 卢米埃支付会员用户服务
     */
    @Autowired
    private LumierePayMemberUserService lumierePayMemberUserService;

    /**
     * litemall车服务
     */
    @Autowired
    private LitemallCartService litemallCartService;

    /**
     * 地区服务
     */
    @Autowired
    private LitemallRegionService regionService;

    /**
     * 商品服务
     */
    @Autowired
    private LitemallGoodsService goodsService;

    /**
     * 目录服务
     */
    @Autowired
    private LitemallCategoryService categoryService;

    /**
     * 店地区服务
     */
    @Autowired
    private LitemallShopRegionService shopRegionService;

    /**
     * 商品地区服务
     */
    @Autowired
    private LitemallGoodsRegionService goodsRegionService;

    /**
     * litemall税务服务
     */
    @Autowired
    private LitemallTaxService litemallTaxService;
    /**
     * 付费会员用户服务
     */
    @Autowired
    private LumierePayMemberUserService payMemberUserService;
    /**
     * 卢米埃支付会员服务
     */
    @Autowired
    private LumierePayMemberService lumierePayMemberService;

    @Autowired
    private LumiereCouponUserService lumiereCouponUserService;

    @Autowired
    private LitemallUserService litemallUserService;

    @Autowired
    private LumiereCouponService lumiereCouponService;

    @Autowired
    private LumiereCouponStrategyService lumiereCouponStrategyService;

    /**
     * 列表
     * 优惠券列表
     *
     * @param userId 用户id
     * @param page   页面
     * @param limit  限制
     * @param sort   排序
     * @param order  订单
     * @return {@link Object}
     */
    @GetMapping("list")
    @LogAnno
    public Object list(@LoginUser Integer userId, @RequestParam(defaultValue = "1") Integer page,
                       @RequestParam(defaultValue = "10000") Integer limit,
                       @Sort @RequestParam(defaultValue = "add_time") String sort,
                       @Order @RequestParam(defaultValue = "desc") String order) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        LitemallUser user = userService.findById(userId);
        List<LumierePayMemberUser> payMemberUsers = lumierePayMemberUserService.listMemberByUserId(userId);

        LitemallCouponExample example = new LitemallCouponExample();
        LitemallCouponExample.Criteria criteria = example.or();
        List<LitemallCoupon> couponList = couponService.queryListInApp(criteria, page, limit, sort, order);


        couponList = couponList.stream().filter(coupon -> {

            //等级会员匹配
            Integer[] memberIds = coupon.getLevelMemberType();

            if (memberIds != null) {
                if (memberIds.length > 0) {
                    for (int i = 0; i < memberIds.length; i++) {
                        if (memberIds[i] == user.getUserLevel().intValue()) {
                            return true;
                        }
                    }
                }
            }

            if (coupon.getMoneyMemberType() != null && coupon.getMoneyMemberType().length > 0) {
                for (int i = 0; i < payMemberUsers.size(); i++) {
                    for (int j = 0; j < coupon.getMoneyMemberType().length; j++) {
                        if (payMemberUsers.get(i).getPayMemberId() == coupon.getMoneyMemberType()[j].intValue()) {
                            return true;
                        }
                    }
                }
            }

            return false;
        }).collect(Collectors.toList());
        return ResponseUtil.okList(couponList);
    }


    /**
     * selectlist
     * 当前购物车下单商品订单可用优惠券
     *
     * @param userId  用户id
     * @param cartIds 购物车id
     * @param shopId  商店id
     * @return {@link Object}
     */
    @GetMapping("selectlist")
    @LogAnno
    public Object selectlist(@LoginUser Integer userId, @RequestParam("cartIds") ArrayList<Integer> cartIds, Integer shopId) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        List<LumierePayMemberUser> payMemberUsers = payMemberUserService.listMemberByUserId(userId);
        BigDecimal maxMemberPer = new BigDecimal(0);
        //会员的倍率
        BigDecimal memberPrice = new BigDecimal(0);
        Integer cityRegionId = getShopRegionId(shopId);
        BigDecimal memberPer = new BigDecimal(0);
        Boolean notOverlay = false;
        //叠加付费会员优惠比例
        for(LumierePayMemberUser payMemberUser : payMemberUsers){
            //获得付费会员
            LumierePayMember payMember = lumierePayMemberService.findById(payMemberUser.getPayMemberId());
            //判断可以在该店使用
            Boolean result = payMember.getShopIds()!=null? ArrayUtil.contains(payMember.getShopIds(), cityRegionId):true;
            //当付费会员允许 汇率叠加
            if(payMember.getIsOverlay()==1 && result &&payMember.getDicountPer() != null){
                memberPer=memberPer.add((payMember.getDicountPer().divide(new BigDecimal(100)))).setScale(2, BigDecimal.ROUND_HALF_UP);
                notOverlay=true;
            }
            //选择一个最高的会员优惠率
            if(payMember.getDicountPer()!=null&&(memberPer.compareTo(payMember.getDicountPer())==-1)){
                maxMemberPer=payMember.getDicountPer();
            }
        }
        //如果没有一个会员叠加，则选择一个最高的会员优惠率
        memberPer=notOverlay==false?maxMemberPer.divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP):memberPer;
        BigDecimal checkedGoodsPrice = new BigDecimal(0.00);

        //计算购物车价格和数量
        List<LitemallCart> carts = new ArrayList<>();
        for (int i = 0; i < cartIds.size(); i++) {
            LitemallCart litemallCart = litemallCartService.findById(cartIds.get(i));
            if (litemallCart != null) {
                carts.add(litemallCart);
                checkedGoodsPrice = checkedGoodsPrice.add(litemallCart.getPrice().multiply(new BigDecimal(litemallCart.getNumber())));
            }
        }
        BigDecimal nowPrice = checkedGoodsPrice;
        if(memberPer.compareTo(new BigDecimal(1))  != 0 ){
            memberPrice = checkedGoodsPrice.compareTo(checkedGoodsPrice.multiply(memberPer)) >= 0?checkedGoodsPrice.multiply(memberPer) : checkedGoodsPrice ;
        }
        checkedGoodsPrice = nowPrice.subtract(memberPrice);

        List<LumiereCouponUser> lumiereCouponUsers = lumiereCouponUserService.list(Wrappers.lambdaQuery(LumiereCouponUser.class)
                .eq(LumiereCouponUser::getUserId, userId));
        List<LumiereCouponUser> couponUsers= couponVerifyService.checkCouponStrategy(lumiereCouponUsers, checkedGoodsPrice,1,shopId,carts.stream().distinct().map(cart->cart.getGoodsId()).collect(Collectors.toList()));

        List<CouponVo> couponVoList = change(couponUsers, checkedGoodsPrice, carts, cityRegionId, userId);
        return ResponseUtil.okList(couponVoList);
    }

    /**
     * 改变
     *
     * @param couponList   优惠券列表
     * @param cPrice       c价格
     * @param carts        车
     * @param cityRegionId 城市区域id
     * @param userId       用户id
     * @return {@link List}<{@link CouponVo}>
     */
    private List<CouponVo> change(List<LumiereCouponUser> couponList, BigDecimal cPrice, List<LitemallCart> carts, Integer cityRegionId, Integer userId) {
        List<CouponVo> couponVoList = new ArrayList<>(couponList.size());
        BigDecimal memberPrice = new BigDecimal(0.00).setScale(2);
        BigDecimal memberPer = new BigDecimal(0);
        if (userId != null) {
            //计算会员优惠价格
            List<LumierePayMemberUser> payMemberUsers = payMemberUserService.listMemberByUserId(userId);
            for (int i = 0; i < payMemberUsers.size(); i++) {
                if (payMemberUsers.get(i).getPayMemberId() != null) {
                    LumierePayMember payMember = lumierePayMemberService.findById(payMemberUsers.get(i).getPayMemberId());
                    boolean flag = false;
                    if(payMember.getShopIds() != null){
                        for (int j = 0; j < payMember.getShopIds().length; j++) {
                            if (payMember.getShopIds()[j].equals(cityRegionId)) {
                                flag = true;
                            }
                        }
                    }else{
                        flag =  true;
                    }

                    if (payMember != null && payMember.getDicountPer() != null && flag) {
                        memberPer = memberPer.add(payMember.getDicountPer().divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP));
                    }
                }
            }
            if(memberPer.compareTo(new BigDecimal(1) ) != 0){
                memberPrice = cPrice.compareTo(cPrice.multiply(memberPer)) >= 0?cPrice.multiply(memberPer) : cPrice;
            }
        }

        for (LumiereCouponUser couponUser : couponList) {
            BigDecimal cartsPrice = cPrice;
            LumiereCoupon coupon = lumiereCouponService.getById(couponUser.getCouponId());
            LumiereCouponStrategy couponStrategy = lumiereCouponStrategyService.getById(couponUser.getStrategyId());

            CouponVo couponVo = new CouponVo();
            //获取地区限制
            if(couponStrategy.getRegions().length!=0){
                List<LitemallRegion> litemallRegions = regionService.findByIds(Arrays.asList(couponStrategy.getRegions()));
                couponVo.setRegional_Restrictions(litemallRegions.stream().map(LitemallRegion::getNameEn).collect(Collectors.toList()));
            }
            couponVo.setCouponUserId(couponUser.getId());
            couponVo.setId(couponUser.getId());
            couponVo.setName(couponStrategy.getName());
            couponVo.setDesc(coupon.getDescr());
            //couponVo.setTag(coupon.get());
            couponVo.setMin(couponStrategy.getMin());
            couponVo.setCode(coupon.getCode().toString());
            couponVo.setPictureUrl(coupon.getPictureUrl());


            if (couponStrategy.getDiscountType() == 2) {
                if (cartsPrice != null) {
                    BigDecimal discountPrice = cartsPrice.multiply(couponStrategy.getDiscountRate()).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP);
                    couponVo.setDiscount(discountPrice);
                }
            } else {
                couponVo.setDiscount(couponStrategy.getDiscount());
            }


            if (cartsPrice != null) {
                BigDecimal checkedGoodsPrice = cartsPrice;
                cartsPrice = cartsPrice.subtract(couponVo.getDiscount());


                //查询门店shopId对应的区域regionId
                BigDecimal taxPrice = new BigDecimal(0.0);

                //税率代码(GST、PST、HST) 税收值 单次计算
                BigDecimal GSTPrice = new BigDecimal(0.00);
                BigDecimal PSTPrice = new BigDecimal(0.00);
                BigDecimal HSTPrice = new BigDecimal(0.00);

                if (carts != null && cityRegionId != null) {
                    for (LitemallCart cart : carts) {


                        LitemallGoodsRegion goodRegion = goodsRegionService.findByGidAndCityId(cart.getGoodsId(), cityRegionId);
                        if (null == goodRegion) {
                            return null;
                        }
                        Integer[] taxTypes = goodRegion.getTaxTypes();

                        //购物车该条记录的商品费用
//            	BigDecimal cartGoodsPrice = cart.getPrice().multiply(new BigDecimal(cart.getNumber()));
                        //优惠后商品单价
//            	BigDecimal afterDiscountPrice = cart.getPrice().multiply(actualGoodsPrice).divide(checkedGoodsPrice).setScale(2, BigDecimal.ROUND_HALF_UP);
                        BigDecimal afterDiscountPrice = checkedGoodsPrice.compareTo(BigDecimal.ZERO) > 0 ? cart.getPrice().multiply(new BigDecimal(1).subtract(memberPer)).multiply(cartsPrice).divide(checkedGoodsPrice, 2, BigDecimal.ROUND_HALF_UP) : BigDecimal.ZERO;
                        BigDecimal afterDiscountGoodsPrice = afterDiscountPrice.multiply(new BigDecimal(cart.getNumber()));
                        for (int j = 0; j < taxTypes.length; j++) {
                            Integer taxType = taxTypes[j];
                            LitemallTax litemallTax = litemallTaxService.findById(taxType);
                            if (null == litemallTax) {
                                return null;
                            } else if (litemallTax.getDeleted() || (!litemallTax.getEnable())) {
                                continue;
                            }
                            BigDecimal value = litemallTax.getValue();
                            switch (litemallTax.getCode()){
                                case "GST":
                                    GSTPrice=afterDiscountGoodsPrice.compareTo(BigDecimal.ZERO) > 0 ? GSTPrice.add(afterDiscountGoodsPrice.multiply(value).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP)) : BigDecimal.ZERO;
                                    break;
                                case "HST":
                                    HSTPrice=afterDiscountGoodsPrice.compareTo(BigDecimal.ZERO) > 0 ? HSTPrice.add(afterDiscountGoodsPrice.multiply(value).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP)) : BigDecimal.ZERO;
                                    break;
                                //要么是 PST
                                default:
                                    PSTPrice=afterDiscountGoodsPrice.compareTo(BigDecimal.ZERO) > 0 ? PSTPrice.add(afterDiscountGoodsPrice.multiply(value).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP)) : BigDecimal.ZERO;
                            }
                            //获取税收值
                            //BigDecimal value = litemallTax.getValue();
                            //taxPrice = afterDiscountGoodsPrice.compareTo(BigDecimal.ZERO) > 0 ? taxPrice.add(afterDiscountGoodsPrice.multiply(value).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP)) : BigDecimal.ZERO.setScale(2);
                        }
                    }
                }
                //税率代码(GST、PST、HST) 税收值 单计
                couponVo.setGSTPrice(GSTPrice);
                couponVo.setPSTPrice(PSTPrice);
                couponVo.setHSTPrice(HSTPrice);
                couponVo.setTaxPrice(GSTPrice.add(PSTPrice).add(HSTPrice).setScale(2));
            }


            couponVo.setStartTime(couponUser.getStartTime());
            couponVo.setEndTime(couponUser.getEndTime());
            couponVo.setDiscountRate(couponStrategy.getDiscountRate().byteValue());
            couponVo.setDiscountType(couponStrategy.getDiscountType());
            couponVo.setRanges(couponStrategy.getRanges());
            couponVo.setUseLimit(couponStrategy.getUseLimit());
            couponVo.setUseLimitNum(couponStrategy.getUseLimitNum());


            couponVo.setMemberPrice(memberPrice.setScale(2,BigDecimal.ROUND_HALF_UP));

//            //拼接指定商品，指定分类，指定地区
            String userInstruction = "";


            if (couponStrategy.getUseInstruction() != null) {
                userInstruction += "其他说明如下: " + "\r\n";
                userInstruction += "          " + couponStrategy.getUseInstruction() + "\r\n";
                couponVo.getLimitUseInstruction().add(couponStrategy.getUseInstruction());
            }

            couponVo.setUseInstruction(userInstruction);
            couponVoList.add(couponVo);
        }

        return couponVoList;
    }


    /**
     * 收到
     * 优惠券领取
     *
     * @param userId 用户ID
     * @param body   请求内容， { couponId: xxx }
     * @return 操作结果
     */
    @PostMapping("receive")
    @LogAnno
    public Object receive(@LoginUser Integer userId, @RequestBody String body) {
        if (userId == null) {return ResponseUtil.unlogin();}

        Integer couponId = JacksonUtil.parseInteger(body, "couponId");
        if (couponId == null) {return ResponseUtil.badArgument();}

        LitemallCoupon coupon = couponService.findById(couponId);
        if (coupon == null) {return ResponseUtil.badArgumentValue();}

        //账户已领取的优惠券是否超过单人可领取的数量
        long receiveNum = couponUserService.count(Wrappers.lambdaQuery(LitemallCouponUser.class)
                .eq(LitemallCouponUser::getUserId, userId)
                .eq(LitemallCouponUser::getCouponId, couponId));
        if (coupon.getLimit()!=0&&receiveNum == coupon.getLimit()) {
            return ResponseUtil.fail(WxResponseCode.COUPON_EXCEED_OVER_LIMIT, "领取优惠券上限，领取失败");
        }

        // 当前已领取数量和总数量比较
        Integer total = coupon.getTotal();
        Integer totalCoupons = couponUserService.countCoupon(couponId);
        if ((total != 0) && (totalCoupons >= total)) {
            return ResponseUtil.fail(WxResponseCode.COUPON_EXCEED_LIMIT, "优惠券已领完");
        }

        // 当前用户已领取数量和用户限领数量比较
        Integer limit = coupon.getLimit().intValue();
        Integer userCounpons = couponUserService.countUserAndCoupon(userId, couponId);
        if ((limit != 0) && (userCounpons >= limit)) {
            return ResponseUtil.fail(WxResponseCode.COUPON_EXCEED_LIMIT, "优惠券已经领取过");
        }

        // 优惠券分发类型
        // 例如注册赠券类型的优惠券不能领取
        Short type = coupon.getType();
        if (type.equals(Constants.TYPE_CODE)) {
            return ResponseUtil.fail(WxResponseCode.COUPON_RECEIVE_FAIL, "优惠券类型为推广券");
        } else if (type.equals(Constants.TYPE_BARCODE)) {
            return ResponseUtil.fail(WxResponseCode.COUPON_RECEIVE_FAIL, "优惠券类型为实体券");
        }

        // 优惠券状态，已下架或者过期不能领取
        Short status = coupon.getStatus();
        if (status.equals(Constants.COUPON_STATUS_OUT)) {
            return ResponseUtil.fail(WxResponseCode.COUPON_EXCEED_LIMIT, "优惠券已领完");
        } else if (status.equals(Constants.COUPON_STATUS_EXPIRED)) {
            return ResponseUtil.fail(WxResponseCode.COUPON_RECEIVE_FAIL, "优惠券已经过期");
        }
        Snowflake snowflake = IdUtil.createSnowflake(1, 1);
        // 用户领券记录
        LitemallCouponUser couponUser = new LitemallCouponUser();
        couponUser.setCouponId(couponId);
        couponUser.setUserId(userId);
        couponUser.setCode(String.valueOf(snowflake.nextId()));
        Short timeType = coupon.getTimeType();
        if (timeType.equals(Constants.TIME_TYPE_TIME)) {
            couponUser.setStartTime(coupon.getStartTime());
            couponUser.setEndTime(coupon.getEndTime());
        } else {
            LocalDateTime now = LocalDateTime.now();
            couponUser.setStartTime(now);
            couponUser.setEndTime(now.plusDays(coupon.getDays()));
        }
        couponUserService.add(couponUser);

        return ResponseUtil.ok("领取成功");
    }

    /**
     * 交换
     * 优惠券兑换
     *
     * @param userId 用户ID
     * @param body   请求内容， { code: xxx }
     * @return 操作结果
     */
    @PostMapping("exchange")
    @LogAnno
    public Object exchange(@LoginUser Integer userId, @RequestBody String body) {
        if (userId == null) {
            return ResponseUtil.unlogin();
        }
        String code = JacksonUtil.parseString(body, "code");
        if (code == null) {
            return ResponseUtil.badArgument();
        }
        //领取新的券
        LumiereCouponUser lumiereCouponUser = lumiereCouponUserService.getOne(Wrappers.lambdaQuery(LumiereCouponUser.class)
                .eq(LumiereCouponUser::getCode, code));
        if(ObjectUtil.isNull(lumiereCouponUser)){
            return ResponseUtil.fail(WxResponseCode.COUPON_CODE_INVALID, "优惠券不正确");
        }
        if(lumiereCouponUser.getUserId()!=null){
            return ResponseUtil.fail(WxResponseCode.COUPON_EXCEED_LIMIT, "优惠券已兑换");
        }
        if(LocalDateTime.now().isAfter(lumiereCouponUser.getEndTime())){
            return ResponseUtil.fail(WxResponseCode.COUPON_RECEIVE_FAIL, "优惠券已经过期");
        }
        LitemallUser user = litemallUserService.findById(userId);
        lumiereCouponUser.setUserId(userId);
        lumiereCouponUser.setUserName(user.getUsername());
        return lumiereCouponUserService.updateById(lumiereCouponUser)? ResponseUtil.ok("兑换成功"): ResponseUtil.fail("兑换失败");
    }




    /**
     * 得到车间区域id
     *
     * @param shopId 商店id
     * @return {@link Integer}
     */
    private Integer getShopRegionId(Integer shopId) {
        List<LitemallShopRegion> litemallShopRegions = shopRegionService.queryByShopId(shopId);
        if (!CollectionUtils.isEmpty(litemallShopRegions)) {
            for (LitemallShopRegion litemallShopRegion : litemallShopRegions) {
                LitemallRegion litemallRegion = regionService.findById(litemallShopRegion.getRegionId());
                if (Constants.REGION_TYPE_CITY == litemallRegion.getType()) {
                    return litemallShopRegion.getRegionId();
                }
            }
        }
        return null;
    }

}
